/*
 * Copyright 2021-2022 by Nedim Sabic Sabic
 * https://www.fibratus.io
 * All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package etw

import (
	"github.com/stretchr/testify/assert"
	"golang.org/x/sys/windows"
	"testing"
	"unsafe"
)

func TestReadBuffer(t *testing.T) {
	var tests = []struct {
		buf        []byte
		assertions func(t *testing.T, ev *EventRecord)
	}{
		{
			[]byte{
				0x70, 0x3B, 0xD1, 0x24, 0x8E, 0xD6, 0xFF, 0xFF, 0x9C, 0x02, 0x00, 0x00, 0x2C, 0x00, 0x5C, 0x00,
				0x52, 0x00, 0x45, 0x00, 0x47, 0x00, 0x49, 0x00, 0x53, 0x00, 0x54, 0x00, 0x52, 0x00, 0x59, 0x00,
				0x5C, 0x00, 0x55, 0x00, 0x53, 0x00, 0x45, 0x00, 0x52, 0x00, 0x5C, 0x00, 0x53, 0x00, 0x2D, 0x00,
				0x31, 0x00, 0x2D, 0x00, 0x35, 0x00, 0x2D, 0x00, 0x32, 0x00, 0x31, 0x00, 0x2D, 0x00, 0x32, 0x00,
				0x32, 0x00, 0x37, 0x00, 0x31, 0x00, 0x30, 0x00, 0x33, 0x00, 0x34, 0x00, 0x34, 0x00, 0x35, 0x00,
				0x32, 0x00, 0x2D, 0x00, 0x32, 0x00, 0x36, 0x00, 0x30, 0x00, 0x36, 0x00, 0x32, 0x00, 0x37, 0x00,
				0x30, 0x00, 0x30, 0x00, 0x39, 0x00, 0x39, 0x00, 0x2D, 0x00, 0x39, 0x00, 0x38, 0x00, 0x34, 0x00,
				0x38, 0x00, 0x37, 0x00, 0x31, 0x00, 0x35, 0x00, 0x36, 0x00, 0x39, 0x00, 0x2D, 0x00, 0x31, 0x00,
				0x30, 0x00, 0x30, 0x00, 0x31, 0x00, 0x00, 0x00},
			func(t *testing.T, ev *EventRecord) {
				assert.Equal(t, uint64(18446698504724233072), ev.ReadUint64(0))
				assert.Equal(t, uint64(0), ev.ReadUint64(ev.BufferLen+20))
				assert.Equal(t, uint32(668), ev.ReadUint32(8))
				assert.Equal(t, uint16(44), ev.ReadUint16(12))
				assert.Equal(t, "\\REGISTRY\\USER\\S-1-5-21-2271034452-2606270099-984871569-1001", ev.ConsumeUTF16String(14))
			},
		},
		{
			[]byte{
				0x80, 0xE0, 0x2E, 0x49, 0x06, 0xC1, 0xFF, 0xFF, 0xE8, 0x30, 0x00, 0x00, 0x78, 0x14, 0x00, 0x00,
				0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x50, 0x22, 0x91, 0x03, 0x00, 0x00, 0x00,
				0x00, 0x00, 0x00, 0x00, 0xE0, 0x08, 0xE2, 0x1F, 0x0F, 0xA7, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
				0x0F, 0xA7, 0xFF, 0xFF, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x12, 0x00, 0x00, 0x00,
				0x63, 0x6D, 0x64, 0x2E, 0x65, 0x78, 0x65, 0x00, 0x43, 0x00, 0x3A, 0x00, 0x5C, 0x00, 0x57, 0x00,
				0x49, 0x00, 0x4E, 0x00, 0x44, 0x00, 0x4F, 0x00, 0x57, 0x00, 0x53, 0x00, 0x5C, 0x00, 0x73, 0x00,
				0x79, 0x00, 0x73, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6D, 0x00, 0x33, 0x00, 0x32, 0x00, 0x5C, 0x00,
				0x63, 0x00, 0x6D, 0x00, 0x64, 0x00, 0x2E, 0x00, 0x65, 0x00, 0x78, 0x00, 0x65, 0x00, 0x20, 0x00,
				0x2F, 0x00, 0x63, 0x00, 0x20, 0x00, 0x64, 0x00, 0x69, 0x00, 0x72, 0x00, 0x20, 0x00, 0x2F, 0x00,
				0x2D, 0x00, 0x43, 0x00, 0x20, 0x00, 0x2F, 0x00, 0x57, 0x00, 0x20, 0x00, 0x22, 0x00, 0x5C, 0x00,
				0x5C, 0x00, 0x3F, 0x00, 0x5C, 0x00, 0x63, 0x00, 0x3A, 0x00, 0x5C, 0x00, 0x55, 0x00, 0x73, 0x00,
				0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x5C, 0x00, 0x6E, 0x00, 0x65, 0x00, 0x64, 0x00, 0x6F, 0x00,
				0x5C, 0x00, 0x41, 0x00, 0x70, 0x00, 0x70, 0x00, 0x44, 0x00, 0x61, 0x00, 0x74, 0x00, 0x61, 0x00,
				0x5C, 0x00, 0x52, 0x00, 0x6F, 0x00, 0x61, 0x00, 0x6D, 0x00, 0x69, 0x00, 0x6E, 0x00, 0x67, 0x00,
				0x5C, 0x00, 0x52, 0x00, 0x61, 0x00, 0x62, 0x00, 0x62, 0x00, 0x69, 0x00, 0x74, 0x00, 0x4D, 0x00,
				0x51, 0x00, 0x5C, 0x00, 0x64, 0x00, 0x62, 0x00, 0x5C, 0x00, 0x72, 0x00, 0x61, 0x00, 0x62, 0x00,
				0x62, 0x00, 0x69, 0x00, 0x74, 0x00, 0x40, 0x00, 0x61, 0x00, 0x72, 0x00, 0x63, 0x00, 0x68, 0x00,
				0x72, 0x00, 0x61, 0x00, 0x62, 0x00, 0x62, 0x00, 0x69, 0x00, 0x74, 0x00, 0x2D, 0x00, 0x6D, 0x00,
				0x6E, 0x00, 0x65, 0x00, 0x73, 0x00, 0x69, 0x00, 0x61, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00,
				0x00, 0x00},
			func(t *testing.T, ev *EventRecord) {
				assert.Equal(t, uint32(12520), ev.ReadUint32(8))
				assert.Equal(t, uint32(5240), ev.ReadUint32(12))

				rawSid, offset := ev.ReadSID(36, true)
				b := uintptr(unsafe.Pointer(&rawSid[0]))
				b += uintptr(8 * 2)

				sid := (*windows.SID)(unsafe.Pointer(b))
				assert.Equal(t, "S-1-5-18", sid.String())

				name, noffset := ev.ReadAnsiString(offset)
				assert.Equal(t, "cmd.exe", name)
				cmdline, _ := ev.ReadUTF16String(noffset)
				assert.Equal(t, "C:\\WINDOWS\\system32\\cmd.exe /c dir /-C /W \"\\\\?\\c:\\Users\\nedo\\AppData\\Roaming\\RabbitMQ\\db\\rabbit@archrabbit-mnesia\"", cmdline)
			},
		},
	}

	for _, tt := range tests {
		ev := &EventRecord{
			BufferLen: uint16(len(tt.buf)),
			Buffer:    uintptr(unsafe.Pointer(&tt.buf[0])),
		}
		tt.assertions(t, ev)
	}
}

func TestID(t *testing.T) {
	ev := &EventRecord{Header: EventHeader{ProviderID: ThreadpoolGUID, EventDescriptor: EventDescriptor{ID: 44}}}
	assert.Equal(t, uint(14439051552138264620), ev.ID())
}
